package com.heima.wemedia.service.impl;


import com.alibaba.fastjson.JSONArray;
import com.aliyun.green20220302.models.ImageModerationResponse;
import com.aliyun.green20220302.models.TextModerationResponseBody;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.apis.article.IArticleClient;
import com.heima.common.aliyun.AutoCheckImg;
import com.heima.common.aliyun.AutoCheckTxt;
import com.heima.common.tess4j.Tess4jUtil;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dots.ApArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
@Transactional
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    private AutoCheckTxt autoCheckTxt;

    @Autowired
    private AutoCheckImg autoCheckImg;

    @Async
    @Override
    public void autoScan(Long apId) {
        //检查文章是否存在
        WmNews wmNews = wmNewsMapper.selectById(apId);
        if (wmNews == null) {
            throw new RuntimeException(this.getClass().getName() + "-文章不存在");
        }

        //判断文章内容是否是待审核
        if (wmNews.getStatus() == WmNews.Status.SUBMIT.getCode()) {
            //从文章内容中抽取出纯文本内容和纯图片(内容的和封面的)的
            Map<String, Object> textAndImage = extractTextAndImage(wmNews);
            //1 自定义敏感词检查
            boolean isSensitiveOk = handleSensitive((String) textAndImage.get("content"), wmNews);
            if (!isSensitiveOk) return;
            //2 文本安全检查 有传入了一个
            boolean isTextOk = handleTextScan((String) textAndImage.get("content"), wmNews);
            if (!isTextOk) return;
            //3 图片安全检查
            boolean isImgsOk = handleImgScan((List<String>) textAndImage.get("imgsPath"), wmNews);
            if (!isImgsOk) return;
            //4 图片ocr检查 图片转文字检查  -- 暂时不用了
            //boolean isOCROk = handleOcr((List<String>) textAndImage.get("imgsPath"), wmNews);
            //if (!isOCROk) return;

            //feign 远程调用
            //图片文章都没问题，保存APP端相关的文章数据，其实就是发布
            ResponseResult result = saveAppArticle(wmNews);
            if (result.getCode() != 200) {
                throw new RuntimeException("文章审核成功，发布失败");
            }
            //如果发布也成功了 设置文章内容 修改文章状态 回填文章id
            wmNews.setArticleId((Long) result.getData());
            wmNews.setStatus(WmNews.Status.PUBLISHED.getCode());
            wmNews.setReason("审核成功");
            wmNewsMapper.updateById(wmNews);
        }


    }

    /**
     * 图片ocr检查  识别图片中的文字
     * @param imgsPath
     * @param wmNews
     * @return
     */
    @Autowired
    private FileStorageService fileStorageService ;
    @Autowired
    private Tess4jUtil tess4jUtil ;

    private boolean handleOcr(List<String> imgsPath, WmNews wmNews) {

        boolean flag = true;

        try {
            for (String s : imgsPath) {
                //下载图片
                byte[] bytes = fileStorageService.downLoadFile(s);
                ByteArrayInputStream in =new ByteArrayInputStream(bytes);
                BufferedImage read = ImageIO.read(in);
                String txtInImg = tess4jUtil.doOCR(read);
                boolean b = handleSensitive(txtInImg, wmNews);
                if (!b){
                    flag = false;
                    return  flag  ;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return flag ;
    }

    /**
     * 自定义敏感词检查
     *
     * @param content
     * @param wmNews
     * @return
     */
    @Autowired
    private WmSensitiveMapper sensitiveMapper;

    private boolean handleSensitive(String content, WmNews wmNews) {
        boolean flag = true;
        List<WmSensitive> wmSensitives = sensitiveMapper.selectList(Wrappers.<WmSensitive>lambdaQuery().select(WmSensitive::getSensitives));
        //集合中的泛型是WmSensitive对象，要转为string
        List<String> collect = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
        SensitiveWordUtil.initMap(collect);
        Map<String, Integer> stringIntegerMap = SensitiveWordUtil.matchWords(content);
        if (stringIntegerMap.size() > 0) {
            //内容不安全
            wmNews.setStatus(WmNews.Status.FAIL.getCode());
            wmNews.setReason("包含违规内容" + stringIntegerMap);
            wmNewsMapper.updateById(wmNews);
            flag = false;
        }
        return flag;

    }

    /***
     * 远程调用保存app端文章
     * @param wmNews
     */
    @Autowired //使用feign时候，一定要开启feign的远程调用 在启动类添加
    private IArticleClient iArticleClient;

    @Autowired
    private WmChannelMapper channelMapper;

    @Autowired
    private WmUserMapper wmUserMapper;

    private ResponseResult saveAppArticle(WmNews wmNews) {
        ApArticleDto dto = new ApArticleDto();
        BeanUtils.copyProperties(wmNews, dto);
        //属性补全
        dto.setLayout(wmNews.getType().intValue());
        //频道名
        WmChannel wmChannel = channelMapper.selectById(wmNews.getChannelId());
        if (wmChannel != null) {
            dto.setChannelName(wmChannel.getName());
        }
        //作者
        dto.setAuthorId(wmNews.getUserId());
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        if (wmUser != null) {
            dto.setAuthorName(wmUser.getName());
        }

        //文章id
        if (wmNews.getId() != null) {
            dto.setId(wmNews.getArticleId());
        }
        dto.setCreatedTime(new Date());

        ResponseResult result = iArticleClient.saveArticle(dto);  //返回对象里面包含了文章id
        return result;
    }

    /**
     * 图片安全检查方法
     *
     * @param imgsPath 图片url列表
     * @param wmNews   自媒体文章
     * @return
     */
    private boolean handleImgScan(List<String> imgsPath, WmNews wmNews) {
        boolean isPass = true;

        if (imgsPath.size() == 0) {
            return isPass;
        }

        boolean checkRes[] = new boolean[imgsPath.size()];

        for (int i = 0; i < checkRes.length; i++) {
            try {
                ImageModerationResponse response = autoCheckImg.checkImgByUrl(imgsPath.get(i));
                if (response != null) {
                    int errorNum = response.getBody().getData().getResult().size();
                    if (errorNum <= 1) { //因为当图片没有问题的时候还是会返回一个label，为了方便让一个label的时候都检查通过
                        //正常
                        checkRes[i] = true;
                    } else {
                        //异常
                        checkRes[i] = false;
                    }
                } else {
                    throw new RuntimeException("图片检查异常");
                }
            } catch (Exception e) {
                log.error(imgsPath.get(i) + "-图片检查异常");
                e.printStackTrace();
            }
        }

        for (boolean checkRe : checkRes) {
            if (checkRe == false) {
                isPass = false;
                break;
            }
        }

        if (isPass) {
            //通过修改文章信息
            wmNews.setReason("图片检查通过");
            wmNews.setStatus(WmNews.Status.SUCCESS.getCode()); //审核通过未发布
            wmNewsMapper.updateById(wmNews);
        } else {
            wmNews.setReason("图片检查未通过");
            wmNews.setStatus(WmNews.Status.FAIL.getCode()); //审核通过未发布
            wmNewsMapper.updateById(wmNews);
        }
        return isPass;
    }

    /**
     * 文本安全性检查
     *
     * @param content 要检查的内容
     * @param wmNews  新闻对象，检测成功或者失败后，要修改文章状态
     * @return
     */
    private boolean handleTextScan(String content, WmNews wmNews) {

        boolean isPass = true;

        //判断内容是否空白，空白直接返回true
        if ((wmNews.getTitle() + "-" + content).length() == 1) {
            return isPass;
        }

        try {
            TextModerationResponseBody resp = autoCheckTxt.checkMsg(content);
            if (resp != null) {
                if ((resp.getData().getLabels().contains(",")) && (resp.getData().getLabels().split(",").length > 0)) {
                    //如果错误原因大于0 认为违规 设置文章状态为审核通过待发布
                    wmNews.setStatus(WmNews.Status.FAIL.getCode());
                    wmNews.setReason("文章中存在违规内容");
                    wmNewsMapper.updateById(wmNews);

                    isPass = false;

                } else {
                    //老师还分了一个文章中存在不确定信息 ，我这里就不区分了，要么成功要么就失败
                    //如果错误原因大于0 认为违规 设置文章状态为审核通过待发布
                    wmNews.setStatus(WmNews.Status.SUCCESS.getCode());
                    wmNews.setReason("文章审核通过");
                    wmNewsMapper.updateById(wmNews);
                    isPass = true;
                }
            } else {
                isPass = false;
                throw new RuntimeException("文章审核异常");
            }

        } catch (Exception e) {
            isPass = false;
            log.error(this.getClass().getName() + "-文本安全检查异常");
            e.printStackTrace();
        }
        return isPass;

    }

    private Map<String, Object> extractTextAndImage(WmNews wmNews) {
        //拼接所有的纯文本
        StringBuilder sb = new StringBuilder();
        //存放图片访问路径
        List<String> imgsPath = new ArrayList<>();

        String content = wmNews.getContent();
        List<Map> maps = JSONArray.parseArray(content, Map.class);
        //拿到里面所有的键是text的map
        for (Map map : maps) {
            if (map.get("type").equals("text")) {
                sb.append(map.get("value"));
            }

            if (map.get("type").equals("image")) {
                imgsPath.add((String) map.get("value"));
            }
        }
        //拿到文章封面（可能有多张）放到图片列表中，封面的图片是，号分割的
        String[] split = wmNews.getImages().split(",");
        if ((split != null) && (split.length > 0)) {
            imgsPath.addAll(Arrays.asList(split));
        }
        Map<String, Object> extractRes = new HashMap<>();
        extractRes.put("content", sb.toString());
        extractRes.put("imgsPath", imgsPath);
        return extractRes;
    }


}
